package portes;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import bibliotheque.Algo;
import bibliotheque.AlgoDiffusion;
import bibliotheque.AlgoHorlogeLogique;
import bibliotheque.AlgoJeton;
import reso.Client;
import reso.Reso;
import reso.Launcher;
import voitures.ServeurVoitures;

public class PorteImpl extends UnicastRemoteObject implements Porte, Client{
	
	// L'algorithme encapsulé, de type Algo
	private Algo algorithme;
	private Reso reso;
	// l'id de la porte
	private int id;
	// utilisé pour les logs
	File file; 
	
	public PorteImpl() throws RemoteException {
		super();
		// à la création, la porte se déclare au Reso
		try {
			this.reso = (Reso) Naming.lookup(Reso.NAME);
			this.id = reso.declareClient(this);
			System.out.println("[Porte " + id + "] déclarée au Reso");
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Accéder à l'id de la porte (utile pour l'algorithme encapsulé)
	 * 
	 * @throws RemoteException
	 */
	public int getId(){
		return this.id;
	}
	public static void main(String[] args) throws RemoteException, InterruptedException, MalformedURLException, NotBoundException {
		Launcher.setServerHostname();
		PorteImpl porte = new PorteImpl();
	
		// Choix du type d'algorithme encapsulé
		porte.algorithme = new AlgoHorlogeLogique(porte);

		// au lancement, la porte se déclare au serveur de voitures
		ServeurVoitures serveur = (ServeurVoitures) Naming.lookup(ServeurVoitures.NAME);
		serveur.ajouterPorte(porte);
		System.out.println("[Porte " + porte.getId() + "] déclarée au serveur de voitures");
	}
	
	/**
	 * Méthode appelée par ServeurVoituresImpl pour annoncer le démarage
	 * une fois que toutes les portes sont déclarées.
	 * @throws RemoteException 
	 */
	@Override
	public void init() throws RemoteException {
		// on supprime un éventuel fichier de log existant
		File file = new File("Trace_" + id + ".txt");
		file.delete();
		this.algorithme.init();
	}
	
	@Override
	/**
	 * Recevoir un message d'une autre Porte (passant par le Reso).
	 * Le message est transmis à l'algorithme encapsulé pour traitement.
	 * 
	 * @param from id de la Porte qui envoie le message.
	 * @param to id de la Porte qui reçoit le message (normalement la Porte elle-même !).
	 * @param msg le message reçu.
	 * @throws RemoteException
	 */
	public void receiveMessage(int from, int to, Serializable msg) throws RemoteException {
		algorithme.receiveMessage(from, to, msg);
	}

	@Override
	/**
	 * Envoyer un message à une autre Porte (passant par le Reso)
	 * Cette méthode est appelée par l'algorithme encapsulé.
	 * 
	 * @param from id de la Porte qui envoie le message (normalement la Porte elle-même !).
	 * @param to id de la Porte à qui envoyer le message.
	 * @param msg le message envoyé.
	 * @throws RemoteException
	 */
	public void sendMessage(int from, int to, Serializable msg)	throws RemoteException {
		reso.sendMessage(from, to, msg);
	}
	
	@Override
	/**
	 * Recevoir une demande d'entrée d'une voiture. Cette méthode distante est appellée par ServeurVoitureImpl.
	 * Le traitement de la demande est géré par l'algorithme encapsulé via sa méthode de même nom.
	 * 
	 */
	public void demandeEntree() throws RemoteException, InterruptedException {
		algorithme.demandeEntree();
	}

	@Override
	/**
	 * Recevoir une demande de sortie d'une voiture. Cette méthode distante est appellée par ServeurVoitureImpl.
	 * Le traitement de la demande est géré par l'algorithme encapsulé via sa méthode de même nom.
	 * 
	 */
	public void demandeSortie() throws RemoteException, InterruptedException {
		algorithme.demandeSortie();
	}
	
	// pour le fichier de log
	public void log(String content){
		try {
			File file = new File("Trace_" + id + ".txt");
			if(!file.exists())
				file.createNewFile();
			//true = append file
    		FileWriter fileWritter = new FileWriter(file.getName(),true);
    	        BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
    	        bufferWritter.write(content);
    	        System.out.println(content);
    	        bufferWritter.newLine();
    	        bufferWritter.close();
    	        
		} catch (IOException e) {e.printStackTrace();}
	}
	
}
